home *** CD-ROM | disk | FTP | other *** search
- /* **************************************************************************
- * Copyright (c) 1993, BSDI. All rights reserved.
- * Library Name... Object Engine
- * File Name...... objeng.cpp
- * Comments....... This file contains the definitions for the core of the
- * object engine.
- *
- * ***************************************************************************/
-
- #ifdef _Windows
- #include <windows.h>
- #else
- #include <conio.h>
- #endif
- #include <stdio.h>
- #include <stdlib.h>
- #include "objeng.hpp"
-
- extern ObjEng objeng;
-
- //-----------------------------------------------------------
- #ifdef _Windows
- ObjEng::ObjEng(char *clientName, int shareMode, int bufsize, int maxContainer, int saveChanges, char *fd)
- #else
- ObjEng::ObjEng(int bufsize, int maxContainer, int saveChanges, char *fd)
- #endif
- {
- PXSetDefaults(bufsize, maxContainer, maxContainer * 2, PXDEFAULT, PXDEFAULT, PXDEFAULT);
- #ifdef _Windows
- if ((status = PXWinInit(clientName, shareMode)) != PXSUCCESS) return;
- #else
- if ((status = PXInit()) != PXSUCCESS) return;
- #endif
- OESaveChanges = saveChanges;
-
- strcpy(filedir, fd);
- int i = strlen(filedir); //Assuming usually WON'T have \
- if (filedir[i - 1] != '\\')
- {
- filedir[i] = '\\';
- filedir[i + 1] = 0;
- }
- for (i = 0; i < OE_MAXTABLES; i++)
- {
- memset(&RegisteredTables[i], 0, sizeof(OEHandle));
- }
- TableInit();
- }
-
-
- //-----------------------------------------------------------
- #ifdef _Windows
- ObjEng::ObjEng(char *clientName) //Uses all defaults.
- #else
- ObjEng::ObjEng() //Uses all defaults.
- #endif
- {
- #ifdef _Windows
- if ((status = PXWinInit(clientName, PXSHARED)) != PXSUCCESS) return;
- #else
- if ((status = PXInit()) != PXSUCCESS) return;
- #endif
- OESaveChanges = TRUE;
- strcpy(filedir, ".\\");
- TableInit();
- }
-
-
- //-----------------------------------------------------------
- ObjEng::~ObjEng()
- {
- PXTblClose(tHdl);
- // Must close all of the tHdls in the RegisteredTables list.
- for (int i = 0; i < OE_MAXTABLES; i++)
- {
- if (RegisteredTables[i].tHdl != 0)
- PXTblClose(RegisteredTables[i].tHdl);
- else
- break;
- }
- PXExit();
- }
-
-
- //-----------------------------------------------------------
- int ObjEng::TableInit()
- {
- char dbname[76];
- int bExist;
-
- strcpy(dbname, filedir);
- strcat(dbname, "objeng"); //User name of objeng should cause error.
- PXTblExist( dbname, &bExist );
- if ( ! bExist )
- {
- char *fldnames[] = {"ID", "ChildID", "TblName"};
- char *types[] = {"N", "N", "A12"};
- FIELDHANDLE IdxFlds[] = { 1, 2 };
- if ((status = PXTblCreate( dbname, 3, fldnames, types )) != PXSUCCESS) return status;
- if ((status = PXKeyAdd( dbname, 2, IdxFlds, PRIMARY )) != PXSUCCESS) return status;
- if ((status = PXTblOpen( dbname, &tHdl, 0, 1)) != PXSUCCESS) return status;
- if ((status = PXRecBufOpen(tHdl, & rHdl)) != PXSUCCESS) return status;
- PXPutLong(rHdl, 1, 0L);
- PXPutLong(rHdl, 2, 10L);
- PXPutAlpha(rHdl, 3, "Root");
- PXRecInsert(tHdl, rHdl);
- PXPutLong(rHdl, 1, 1L); //Sub-object lists.
- PXRecInsert(tHdl, rHdl);
- }
- else
- {
- if ((status = PXTblOpen( dbname, &tHdl, 0, 1)) != PXSUCCESS) return status;
- if ((status = PXRecBufOpen(tHdl, & rHdl)) != PXSUCCESS) return status;
- }
- return status;
- }
-
-
- //-----------------------------------------------------------
- // The object engine management table has two records (ID=0 and ID=1)
- // to provide counters for Objects and for Lists (respectively).
- // After these two (starting at 10) come the List/TableName/Object tuples.
- // Each of these tuples represents an element on one list and its
- // associated table name and objectID. When a list is created it is empty.
- // As it is filled, this table stays in synch so it can be pulled out again
- // later.
- // To find any element on a list, find the record in the named data table
- // with the given objectID. We must call a function (defined after the
- // objeng header has been processed) that lines up defined classes and
- // the named tables.
- int ObjEng::GetIndex(long &index, int listFlag)
- {
- if (listFlag == TRUE) PXPutLong(rHdl, 1, 1L);
- else PXPutLong(rHdl, 1, 0L);
- if ((status = PXSrchKey(tHdl, rHdl, 1, SEARCHFIRST)) != PXSUCCESS) return status;
- if ((status = PXRecGet(tHdl, rHdl)) != PXSUCCESS) return status;
- PXGetLong(rHdl, 2, &index);
- PXPutLong(rHdl, 2, index+1);
- return (status = PXRecUpdate(tHdl, rHdl));
- }
-
-
- //-----------------------------------------------------------
- int ObjEng::AttachChild(long &parent, const char *tableName, const long &objectID)
- {
- PXPutLong(rHdl, 1, parent);
- PXPutLong(rHdl, 2, objectID);
- PXPutAlpha(rHdl, 3, (char *)tableName);
- return(status = PXRecInsert(tHdl, rHdl));
- }
-
-
- //-----------------------------------------------------------
- int ObjEng::DetachChild(const long &parent, const long &child)
- {
- PXPutLong(rHdl, 1, parent);
- PXPutLong(rHdl, 2, child);
- if ((status = PXSrchKey(tHdl, rHdl, 2, SEARCHFIRST)) == PXSUCCESS)
- status = PXRecDelete(tHdl);
- return status;
- }
-
-
- //-----------------------------------------------------------
- int ObjEng::GetChild(long &parent, char *tbl, long &child, int mode)
- {
- // Given parent and mode, return tbl & child...
- PXPutLong(rHdl, 1, parent);
- if ((status = PXSrchKey(tHdl, rHdl, 1, mode)) != PXSUCCESS) return status;
- if ((status = PXRecGet(tHdl, rHdl)) != PXSUCCESS) return status;
- PXGetLong(rHdl, 2, &child);
- PXGetAlpha(rHdl, 3, 12, tbl);
- return status;
- }
-
-
- //-----------------------------------------------------------
- int ObjEng::Register(OEHandle &oehandle, char **FieldNames, char **FieldTypes, FIELDHANDLE *IdxFieldHandles, int nFields, int nIdxFields)
- {
- int bExist, i;
- char dbname[76];
-
- // Rename using the file directory stored in dbcc
- strcpy(dbname, filedir);
- strcat(dbname, oehandle.TableName);
- PXTblExist( dbname, &bExist );
- if ( ! bExist )
- {
- // Create table and primary index
- if ((status = PXTblCreate( dbname, nFields, FieldNames, FieldTypes)) != PXSUCCESS) return status;
- if (nIdxFields > 0)
- {
- if ((status = PXKeyAdd( dbname, nIdxFields, IdxFieldHandles, PRIMARY )) != PXSUCCESS) return status;
- }
- }
-
- // Find match or advance to next open slot...
- for (i = 0; i < OE_MAXTABLES; i++)
- {
- if ((strcmp(RegisteredTables[i].TableName, oehandle.TableName) == 0) ||
- (RegisteredTables[i].tHdl == 0))
- break;
- }
- // If nothing was found, then copy the tablename in and move on to the
- // Table and Record Open fns to fill in the tHdl and rHdl vars.
- if (RegisteredTables[i].tHdl == 0)
- {
- strcpy(RegisteredTables[i].TableName, oehandle.TableName);
- if ((status = PXTblOpen(dbname, &(RegisteredTables[i].tHdl), 0, OESaveChanges)) != PXSUCCESS) return status;
- if ((status = PXRecBufOpen(RegisteredTables[i].tHdl, &(RegisteredTables[i].rHdl))) != PXSUCCESS) return status;
- }
- oehandle.tHdl = RegisteredTables[i].tHdl;
- oehandle.rHdl = RegisteredTables[i].rHdl;
- return status;
- }
-
-
- //-----------------------------------------------------------
- int ObjEng::IsRegistered(OEHandle &oehandle)
- {
- for (int i = 0; (i < OE_MAXTABLES) && (RegisteredTables[i].tHdl != 0); i++)
- {
- if (strcmp(RegisteredTables[i].TableName, oehandle.TableName) == 0)
- {
- oehandle.tHdl = RegisteredTables[i].tHdl;
- oehandle.rHdl = RegisteredTables[i].rHdl;
- return TRUE;
- }
- }
- return FALSE;
- }
-
- // $$$$$$$$$$$$$$$$$$$ Persistant Class Definitions $$$$$$$$$$$$$$$$$$$
-
- //-----------------------------------------------------------
- PersistClass::PersistClass(char *name)
- {
- objectID = 0;
- status = PXSUCCESS;
- memset(&oehandle, 0, sizeof(OEHandle));
- strcpy(oehandle.TableName, name);
- }
-
-
- //-------------------------------------------------------
- void PersistClass::Copy(PersistClass &pc)
- {
- objectID = pc.GetObjectID();
- status = pc.status;
- memcpy(&oehandle, &pc.oehandle, sizeof(OEHandle));
- }
-
-
- //-------------------------------------------------------
- void PersistClass::Unlink()
- {
- objectID = 0;
- status = PXSUCCESS;
- }
-
-
- //-------------------------------------------------------
- inline int PersistClass::NRecs(RECORDNUMBER & nrecs)
- {
- return(status = PXTblNRecs(oehandle.tHdl, & nrecs));
- }
-
-
- //-----------------------------------------------------------
- inline int PersistClass::LinkToKey(int, int)
- {
- return PXERR_TABLENOTINDEXED;
- }
-
-
- //-------------------------------------------------------
- int PersistClass::LinkToRecord(int position)
- {
- RECORDNUMBER nrecs;
-
- NRecs(nrecs);
- if ((position > nrecs) || (position < 1))
- return(status = PXERR_OUTOFRANGE);
-
- if ((status = PXRecGoto(oehandle.tHdl, position)) == PXSUCCESS)
- return Retrieve();
- else
- return status;
- }
-
-
- //-----------------------------------------------------------
- int PersistClass::LinkToField(char *fieldname, void *value, int mode)
- {
- FIELDHANDLE fld;
-
- if ((status = PXFldHandle(oehandle.tHdl, fieldname, &fld)) != PXSUCCESS) return status;
-
- switch (localtypes[fld - 1]) // handles start at 1, C arrays at 0
- {
- case 'D' :
- long dbdate;
- struct tm *indate = (struct tm *)value;
-
- PXDateEncode(indate->tm_mon + 1, indate->tm_mday, indate->tm_year, & dbdate);
- PXPutDate(oehandle.rHdl, fld, dbdate);
- break;
- case 'S' :
- PXPutShort(oehandle.rHdl, fld, *(short *)value);
- break;
- case 'L' :
- PXPutLong(oehandle.rHdl, fld, *(long *)value);
- break;
- case '$' :
- PXPutDoub(oehandle.rHdl, fld, double(*(float *)value));
- break;
- case 'N' :
- PXPutDoub(oehandle.rHdl, fld, *(double *)value);
- break;
- case 'A' :
- PXPutAlpha(oehandle.rHdl, fld, (char *)value);
- break;
- default:
- status = PXERR_INVFIELDHANDLE;
- return(status);
- }
- if ((status = PXSrchFld(oehandle.tHdl, oehandle.rHdl, fld, mode)) == PXSUCCESS)
- return Retrieve();
- else
- return status;
- }
-
-
- //-----------------------------------------------------------
- int PersistClass::LinkToID(const long &ID)
- {
- // Cannot use global nFields! (It changes for each derived class!)
- int nFlds;
-
- if (ID == 0) // ID 0 is illegal
- {
- status = PXERR_RECNOTFOUND;
- return status;
- }
- // THIS IS WHY the objectID must ALWAYS be the LAST field.
- PXRecNFlds(oehandle.tHdl, &nFlds);
- PXPutLong(oehandle.rHdl, nFlds, ID);
- if ((status = PXSrchFld(oehandle.tHdl, oehandle.rHdl, nFlds, SEARCHFIRST)) == PXSUCCESS)
- return Retrieve();
- else
- return status;
- }
-
-
- //-------------------------------------------------------
- int PersistClass::LinkToFirst()
- {
- RECORDNUMBER nrecs;
-
- NRecs(nrecs);
- if ((status = PXRecGoto(oehandle.tHdl, nrecs)) == PXSUCCESS)
- return Retrieve();
- else
- return status;
- }
-
-
- //-------------------------------------------------------
- int PersistClass::LinkToLast()
- {
- RECORDNUMBER nrecs;
-
- NRecs(nrecs);
- if ((status = PXRecGoto(oehandle.tHdl, nrecs)) == PXSUCCESS)
- return Retrieve();
- else
- return status;
- }
-
-
- //-------------------------------------------------------
- int PersistClass::LinkToNext()
- {
- if ((status = PXRecNext(oehandle.tHdl)) == PXSUCCESS)
- return Retrieve();
- else
- return status;
- }
-
-
- //-------------------------------------------------------
- int PersistClass::LinkToPrev()
- {
- if ((status = PXRecPrev(oehandle.tHdl)) == PXSUCCESS)
- return Retrieve();
- else
- return status;
- }
-
-
- //-----------------------------------------------------------
- int PersistClass::Destroy()
- {
- // Cannot use global nFields! (It changes for each derived class!)
- int nFlds;
-
- if (objectID == 0) // Not yet added->can't be deleted.
- {
- status = PXERR_RECNOTFOUND;
- return status;
- }
- // THIS IS WHY the objectID must ALWAYS be the LAST field.
- PXRecNFlds(oehandle.tHdl, &nFlds);
- PXPutLong(oehandle.rHdl, nFlds, objectID);
- if ((status = PXSrchFld(oehandle.tHdl, oehandle.rHdl, nFlds, SEARCHFIRST)) != PXSUCCESS) return status;
- objectID = 0;
- return(status = PXRecDelete(oehandle.tHdl));
- }
-
-
- //-------------------------------------------------------
- int PersistClass::OEPutDate(const int &fld, const struct tm & indate)
- {
- long dbdate;
-
- PXDateEncode(indate.tm_mon + 1, indate.tm_mday, indate.tm_year, & dbdate);
- return (PXPutDate(oehandle.rHdl, fld, dbdate));
- }
-
-
- //-------------------------------------------------------
- int PersistClass::OEGetDate(const int &fld, struct tm & indate)
- {
- long dbdate;
-
- if ((status = PXGetDate(oehandle.rHdl, fld, & dbdate)) == PXSUCCESS)
- {
- PXDateDecode(dbdate, & indate.tm_mon, & indate.tm_mday, & indate.tm_year);
- indate.tm_mon--;
- }
- return status;
- }
-
- // *******************************************************************
- // $$$$$$$$$$$$$$$$$$$ Container Class Definitions $$$$$$$$$$$$$$$$$$$
- // *******************************************************************
-
- // *****************************************************************
- // Create a new (empty) OEList.
- // *****************************************************************
- OEList::OEList()
- {
- listID = -1;
- head = NULL;
- cur = NULL;
- referenceCount = 1;
- status = NOTINIT;
- }
-
-
- // *****************************************************************
- // A list whose id is gotten from a parent being retrieved from
- // the database.
- // *****************************************************************
- OEList::OEList(long inID) : listID(inID)
- {
- head = NULL;
- cur = NULL;
- referenceCount = 1;
- status = NOTINIT;
- }
-
-
- // *****************************************************************
- // Initialize a list. We must do this to ensure that whole descendent
- // sets (possibly multi-nested) are not retrieved when a single object
- // is retrieved. If this isn't done then constructing a list whose
- // PersistClass elements contain lists will not work (the inner list
- // construction will screw the table up for the outer list construction).
- // Init a list: is no listID then this is virgin-- simply get a
- // new listID. Otherwise, find all of the associated children and
- // place them in the array.
- // *****************************************************************
- int OEList::Init()
- {
- char tbl[12];
- long childid;
- int mode = SEARCHFIRST;
- PersistClass *temp;
-
- if (status == READY) return(TRUE); //Allows multiple inits...
- if (listID == -1)
- {
- if (objeng.GetIndex(listID, 1) != PXSUCCESS)
- {
- status = FAIL;
- return FALSE;
- }
- else
- status = READY;
- }
- else
- {
- while (objeng.GetChild(listID, tbl, childid, mode) == PXSUCCESS)
- {
- // GetPersistClass takes a table name and an ID
- // and retrieves a PersistClass descendent to place in pcArr.
- // It also CREATES the actual object to be put in there (via NEW).
- if (head == NULL)
- {
- head = GetPersistClass(tbl, childid);
- cur = head;
- cur->next = NULL;
- }
- else
- {
- temp = GetPersistClass(tbl, childid);
- cur->next = temp;
- temp->next = NULL;
- cur = temp;
- }
- cur->SetDeleteFlag(TRUE);
- mode = SEARCHNEXT;
- }
- cur = head;
- status = READY;
- }
- return(TRUE);
- }
-
-
- // *****************************************************************
- OEList::~OEList()
- {
- PersistClass *temp;
-
- if (status != READY) return;
- if (referenceCount > 1)
- {
- #ifdef _Windows
- MessageBox(NULL, "Deleting a list without checking DeleteOK!", "Error", MB_OK | MB_ICONHAND);
- #else
- // clrscr();
- // printf("ERROR! Deleting a list without checking DeleteOK!");
- // getch();
- #endif
- }
- cur = head;
- while (cur != NULL)
- {
- temp = cur->next;
- if (cur->GetDeleteFlag() == TRUE) delete cur;
- cur = temp;
- }
- }
-
-
- // ******************************************************************
- void OEList::Insert(PersistClass *curelem)
- {
- PersistClass *temp;
-
- if (status == NOTINIT) Init();
- if (status != READY) return;
- // Must be stored FIRST to get an Object ID.
- curelem->next = NULL;
- curelem->Store();
- // Now, insert the element after the currently pointed to element.
- if (head == NULL)
- {
- head = curelem;
- cur = curelem;
- }
- else
- {
- if (cur == NULL) //Can't insert after null, place it last...
- {
- // Move to last LIVE element
- cur = head;
- while (cur->next != NULL)
- {
- cur = cur->next;
- }
- }
- // Now, insert it after the current element.
- temp = cur->next;
- cur->next = curelem;
- curelem->next = temp;
- // Now set cur to point to the new element...
- cur = curelem;
- }
-
- // Now set up corresponding object engine cross-link record.
- objeng.AttachChild(listID, curelem->GetTblName(), curelem->GetObjectID());
- }
-
-
- // *****************************************************************************
- // Remove the CURrent element from the list.
- // *****************************************************************************
- void OEList::Remove()
- {
- PersistClass *temp;
-
- if (status == NOTINIT) Init();
- if (status != READY) return;
- if (cur == NULL)
- {
- return;
- }
- if (cur == head)
- {
- head = cur->next;
- temp = cur->next;
- }
- else
- {
- // Zip through the elements until you get to the one right before cur...
- temp = head;
- while ((temp->next != NULL) && (temp->next != cur))
- {
- temp = temp->next;
- }
- if (temp->next == cur) // JUST to make sure...
- {
- temp->next = cur->next;
- }
- }
- // Delete the pointed-to entities
- objeng.DetachChild(listID, cur->GetObjectID());
- if (cur->GetDeleteFlag() == TRUE) delete cur;
- // In effect, moves cur down one...
- cur = temp;
- }
-
-
- // ******************************************************************
- PersistClass * OEList::operator()()
- {
- if (status == NOTINIT) Init();
- if (status != READY) return NULL;
- return(cur);
- }
-
-
- // ******************************************************************
- PersistClass * OEList::operator++(int)
- {
- PersistClass *temp;
-
- temp = cur;
- if (cur != NULL) cur = cur->next;
- return temp;
- }
-
-
- // ******************************************************************
- void OEList::Clear()
- {
- PersistClass *temp;
-
- if (status == NOTINIT) Init();
- if (status != READY) return;
- // Zip through the elements and delete...
- cur = head;
- while (cur != NULL)
- {
- temp = cur->next;
- // Delete the pointed-to entities
- objeng.DetachChild(listID, cur->GetObjectID());
- if (cur->GetDeleteFlag() == TRUE) delete cur;
- cur = temp;
- }
- }
-
-
- // ******************************************************************
- int OEList::Count()
- {
- PersistClass *temp;
- int i = 0;
-
- if (status == NOTINIT) Init();
- if (status != READY) return 0;
- temp = head;
- while (temp != NULL)
- {
- i++;
- temp = temp->next;
- }
- return(i);
- }
-